/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { KEYBOARD_KEY } from '@app-cad/common/Constants';
import { csEvent } from '@app-cad/common/events/EventCenter';
import { wsApi } from '@app-cad/server';
import {
  FormControl,
  FormControlLabel,
  FormLabel,
  Input,
  Radio,
  RadioGroup,
} from '@mui/material';
import i18n from 'i18next';
import { useEffect, useRef, useState } from 'react';
import useStateRef from 'react-usestateref';
import { Matrix4, Vector3 } from 'three-legacy';

import {
  BaseCommand,
  CSPolygon,
  CSys,
  CadScene,
  CommandDialog,
  CommandHint,
  CommandHintStatus,
  EventsRes,
  MathTool,
  SceneGraph,
  cadAppLog,
  useStore,
} from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import { SKETCH_CENTEREVENTS } from '../../../events/SketchEventCenter';

interface LineCommandProps {
  title: string;
  onClose: () => void;
}

interface TrackingData {
  polygon: CSPolygon;
  vertexs: Vector3[];
}

function LineCommand({ title, onClose }: LineCommandProps) {
  const trackingData: TrackingData = {
    polygon: null,
    vertexs: [],
  };
  const updateCmdHighlightId = useStore((state) => state.updateCmdHighlightId);
  // 默认为 XOY 平面
  const faceCSys: CSys = MathTool.createCsysFromPlacement([
    [0, 0, 0],
    [0, 0, 1],
    [1, 0, 0],
  ]);
  // const [planeName, setPlaneName, planeNameRef] = useStateRef('XOY');
  const planeNameRef = useRef('XOY');
  const cadScene = ctx2.cadScene as CadScene;
  const sceneSetup = ctx2.viewer.sceneSetup;
  const assisGroup = cadScene.assisGroup;
  const xAxis = new Vector3(1, 0, 0);
  const yAxis = new Vector3(0, 1, 0);
  const zAxis = new Vector3(0, 0, 1);
  let targetNormal: Vector3 = new Vector3(0, 0, 1);
  const planeNormal: Vector3 = new Vector3(0, 0, 1);
  const planeOrigin: Vector3 = new Vector3(0, 0, 0);
  let centerPoint: Vector3; // 多边形中心点
  let radius: number = 0;
  let endPoint: Vector3; // 矩形终点
  let step = 'none';
  /**
   * 求圆周上等分点的坐标
   * @param {*} r r为半径
   * @param {*} count count为等分个数
   */
  // function getCirclePoints2d(count, r) {
  //   let points = [];
  //   const radians = (Math.PI / count) * 2
  //   for (let i = 0; i < count; i++) {
  //     const x = r * Math.sin(radians * i)
  //     const y = r * Math.cos(radians * i)
  //     points.unshift(new Vector3(x, y, 0))
  //   }
  //   points.unshift(new Vector3(0, r, 0))
  //   return points
  // }

  const [hits, setHits] = useState<string>('');
  const [lineCount, setLineCount, LineCountRef] = useStateRef(3);
  const [type, setType, typeRef] = useStateRef('inner'); //outside, inner
  useEffect(() => {
    registerEvents();

    return () => {
      onDestroy();
    };
  }, []);
  // ========= 鼠标和键盘事件=========
  const registerEvents = () => {
    csEvent()
      .setState('multiple_line')
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, onMouseMove)
      .on(SKETCH_CENTEREVENTS.POINTERUP, onMouseClick)
      .on(SKETCH_CENTEREVENTS.KEYUP, onKeyup)
      .addExit(onDestroy);
  };
  const unregisterEvents = () => {
    csEvent()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, onMouseMove)
      .off(SKETCH_CENTEREVENTS.POINTERUP, onMouseClick)
      .off(SKETCH_CENTEREVENTS.KEYUP, onKeyup)
      .setDefault();
  };
  const onDestroy = () => {
    unregisterEvents();
    releaseObjects();
    onClose();
  };
  const onKeyup = (e: EventsRes<KeyboardEvent>) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      onDestroy();
    } else if (e.key === KEYBOARD_KEY.ENTER) {
      // if (currentStatus === State.DRAW) {
      //   finishDraw()
      //   onDestroy()
      // }
    } else if (e.key === KEYBOARD_KEY.ARROWUP) {
      changePlaneToXOY();
    } else if (e.key === KEYBOARD_KEY.ARROWRIGHT) {
      changePlaneToYOZ();
    } else if (e.key === KEYBOARD_KEY.ARROWLEFT) {
      changePlaneToXOZ();
    } else if (e.key === KEYBOARD_KEY.ARROWDOWN) {
      changePlaneToXOY();
    }
  };
  const onMouseClick = (e: EventsRes) => {
    if (e.button.onLeft) {
      if (step === 'none') {
        centerPoint = sceneSetup.mouseOnPlane(
          e.mouse.x,
          e.mouse.y,
          planeNormal,
          planeOrigin,
        );
        step = 'draw';
        preview();
      } else if (step === 'draw') {
        finishDraw();
        onDestroy();
      }
      // if (currentStatus === State.NONE) {
      //   trackingData.polygon = null
      //   // 鼠标左键，开始绘制
      //   startPoint = sceneSetup.mouseOnPlane(e.layerX, e.layerY, planeNormal, planeOrigin)
      //   currentStatus = State.DRAW
      //   // preview()
      // } else if (currentStatus === State.DRAW) {
      //   currentStatus = State.FINISH
      //   // 鼠标右键，完成
      //   finishDraw()
      //   onDestroy()
      // }
    } else if (e.button.onRight) {
      // currentStatus = State.FINISH
      // 鼠标右键，放弃
      onDestroy();
    }
  };
  const onMouseMove = (e: EventsRes) => {
    // 在面上画圆形
    // const hits = e.hits;
    // if (hits[0]?.face) {
    //   planeOrigin = hits[0].point;
    //   const faceObj = hits[0].face.getMBrepFace()
    //   const tringleVer = faceObj.brepFace.data.tessellation.data[0][0]
    //   const a = new Vector3().fromArray(tringleVer[0])
    //     , b = new Vector3().fromArray(tringleVer[1])
    //     , c = new Vector3().fromArray(tringleVer[2])
    //   const ab = b.clone().sub(a.clone())
    //   const ac = c.clone().sub(a.clone())
    //   let nor = ab.cross(ac).normalize()
    //   planeNormal = nor
    //   faceCSys = faceObj.csys
    // }
    // // startPoint?.clone().x ? faceCSys.origin = new Vector(startPoint.clone().x, startPoint.clone().y, startPoint.clone().z) : ''
    if (step === 'draw') {
      endPoint = sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        planeNormal,
        planeOrigin,
      );
      radius = Math.sqrt(
        Math.pow(centerPoint.x - endPoint.x, 2) +
          Math.pow(centerPoint.y - endPoint.y, 2) +
          Math.pow(centerPoint.z - endPoint.z, 2),
      );
      preview();
    }
  };
  // ========= 鼠标和键盘事件 =========
  // ========= 位置变换 =========
  const changePlaneToXOY = () => {
    changePlane(zAxis, 'XOY');
  };
  const changePlaneToYOZ = () => {
    changePlane(xAxis, 'YOZ');
  };
  const changePlaneToXOZ = () => {
    changePlane(yAxis, 'XOZ');
  };
  const changePlane = (axis: Vector3, type: string) => {
    // planeNormal = axis.clone()
    // setPlaneName(type)
    // planeOrigin = startPoint ? startPoint.clone() : planeNormal.clone()
    // let _xAxis = [] // 局部坐标系的X轴
    // let _zAxis = [] // 局部坐标系的Z轴
    if (type === 'XOY') {
      targetNormal = new Vector3(0, 0, 1);
      // _xAxis = [1, 0, 0]
      // // planeOrigin.z = 0
      // _zAxis = zAxis.clone().toArray()
    } else if (type === 'YOZ') {
      targetNormal = new Vector3(1, 0, 0);
      // _xAxis = [0, 0, 1]
      // // planeOrigin.x = 0
      // _zAxis = xAxis.clone().toArray()
    } else if (type === 'XOZ') {
      targetNormal = new Vector3(0, 1, 0);
      // _xAxis = [1, 0, 0]
      // // planeOrigin.y = 0
      // _zAxis = yAxis.clone().toArray()
    }
    // const placement = [planeOrigin.clone().toArray(), axis.clone().toArray(), _xAxis]
    // const placement = [planeOrigin.clone().toArray(), _zAxis, _xAxis]
    // faceCSys = MathTool.createCsysFromPlacement(placement)
    // if (trackingData.polygon) {
    //   trackingData.polygon && trackingData.polygon.resetCsys(faceCSys)
    //   preview()
    // }
    setHits(
      '点击确定起点，当前绘制平面为 ' + type + ' 平面，按方向键切换绘制平面',
    );
  };
  const finishDraw = async () => {
    if (trackingData.polygon != null) {
      await wsApi.createPolygon(trackingData.vertexs);
    }
  };

  // 释放对象
  const releaseObjects = () => {
    trackingData.polygon && trackingData.polygon.destroy();

    assisGroup.clear();
    SceneGraph.emptyGroup(assisGroup);
    ctx2.viewer.requestRender();

    updateCmdHighlightId('');
  };

  const preview = () => {
    updateVertexs();
    // 绘制矩形
    if (!trackingData.polygon) {
      trackingData.polygon = new CSPolygon({
        vertexs: trackingData.vertexs,
        csys: faceCSys,
        lineWidth: 2,
      });
      trackingData.polygon.addTo(assisGroup);
    } else {
      assisGroup.clear();
      trackingData.polygon = new CSPolygon({
        vertexs: trackingData.vertexs,
        csys: faceCSys,
        lineWidth: 2,
      });
      trackingData.polygon.addTo(assisGroup);
      trackingData.polygon.update({ vertexs: trackingData.vertexs });
    }
    ctx2.viewer.requestRender();
  };
  //
  function calculatePolygonPoints() {
    const angle = 360 / LineCountRef.current; // 计算多边形的角度
    const points = []; // 存储多边形的点
    const bigRadius = radius / Math.cos(((angle / 2) * Math.PI) / 180);
    for (let i = 0; i < LineCountRef.current; i++) {
      const x =
        centerPoint.x + bigRadius * Math.sin((i * angle * Math.PI) / 180); // 将角度转换为弧度并计算点的x坐标
      const y =
        centerPoint.y + bigRadius * Math.cos((i * angle * Math.PI) / 180); // 将角度转换为弧度并计算点的y坐标
      points.push(new Vector3(x, y, 0)); // 将点添加到数组中
    }
    points.push(points[0]);
    return points; // 返回多边形的所有点
  }

  // 更新点的信息
  const updateVertexs = () => {
    if (planeNameRef.current === 'XOY') {
      if (typeRef.current === 'inner') {
        //内切多边形
        const points = [];
        const radians = (Math.PI / LineCountRef.current) * 2;
        for (let i = 0; i < LineCountRef.current; i++) {
          const x = centerPoint.x + radius * Math.sin(radians * i);
          const y = centerPoint.y + radius * Math.cos(radians * i);
          const z = centerPoint.z + radius * Math.cos(radians * i);
          cadAppLog(`updateVertexs[x: ${x}, y: ${y}, z: ${z}]`);
          // points.push(new Vector3(x, y, z))
          points.push(rotate(new Vector3(x, y, 0)));
        }
        points.push(
          rotate(new Vector3(centerPoint.x, centerPoint.y + radius, 0)),
        );
        trackingData.vertexs = points;
      } else {
        // 外切多边形
        trackingData.vertexs = calculatePolygonPoints();
      }
    } else if (planeNameRef.current === 'YOZ') {
      trackingData.vertexs = [
        new Vector3(0, 0, 0),
        new Vector3(0, 100, 0),
        new Vector3(50, 150, 0),
        new Vector3(100, 100, 0),
        new Vector3(100, 0, 0),
        // new Vector3(20, 50, 0),
        new Vector3(0, 0, 0),
      ];
    } else if (planeNameRef.current === 'XOZ') {
      trackingData.vertexs = [
        new Vector3(0, 0, 0),
        new Vector3(0, 100, 0),
        new Vector3(50, 150, 0),
        new Vector3(100, 100, 0),
        new Vector3(100, 0, 0),
        // new Vector3(20, 50, 0),
        new Vector3(0, 0, 0),
      ];
    }
  };
  // 旋转矩阵
  const rotate = (point: Vector3) => {
    //n1当前法向量，n2目标法向量
    const n1 = new Vector3(0, 0, 1);
    const n2 = targetNormal.clone();

    // 计算两个法向量之间的角度θ
    const theta = Math.acos(n1.dot(n2) / (n1.length() * n2.length()));

    // 计算旋转轴
    const axis = n1.cross(n2).normalize();

    // 计算旋转角度
    // var angle = theta * Math.PI;
    // 创建旋转矩阵
    const matrix = new Matrix4();
    matrix.makeRotationAxis(axis, theta);

    const rotatePoint = point.applyMatrix4(matrix);

    return rotatePoint;
    // trackingData.polygon.applyMatrix4(matrix)

    // 将旋转矩阵应用到物体上
    // var object = new THREE.Object3D(); // 要旋转的物体
    // object.position.set(x, y, z); // 物体的位置
    // object.applyMatrix4(matrix); // 应用旋转矩阵
  };
  return (
    <CommandDialog
      title={title}
      onClose={onClose}
      placement={'topLeft'}
    >
      <CommandHint
        status={CommandHintStatus.INFO}
        content={hits}
      />
      <FormControl
        variant='filled'
        sx={{ padding: '0 15px' }}
      >
        <FormLabel>选择多边形类型</FormLabel>
        <RadioGroup
          row
          value={type}
          onChange={(_, value) => {
            setType(value);
            // cmdRef.current.updateAxis(value as Axis)
          }}
        >
          <FormControlLabel
            value='inner'
            control={<Radio size='small' />}
            label='内切多边形'
          />
          <FormControlLabel
            value='outside'
            control={<Radio size='small' />}
            label='外切多边形'
          />
        </RadioGroup>
      </FormControl>
      <FormControl
        variant='filled'
        sx={{ padding: '15px' }}
      >
        {/* <InputLabel htmlFor="angle">输入多边形边数</InputLabel> */}
        <FormLabel>输入多边形边数</FormLabel>
        <Input
          id='angle'
          type='number'
          value={lineCount}
          onChange={(e) => {
            const a = parseFloat(e.target.value);
            if (!Number.isNaN(a) && Number(a) > 2) {
              setLineCount(a);
              // cmdRef.current.do(MathUtils.degToRad(a))
            }
          }}
        />
      </FormControl>
    </CommandDialog>
  );
}
export const cmdMultipleLine: BaseCommand = {
  id: 'CmdMultipleLine',
  label: 'command.polygon',
  icon: 'commands/feature/polygon',
  create: (label: string, onClose: () => void) => (
    <LineCommand
      title={i18n.t(label)}
      onClose={onClose}
    />
  ),
};
